﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace StyleMVVM.Data.Transform
{
	public class TransformPropertyMap<TIn, TOut> : ITransformPropertyMap<TIn, TOut>, ITransformPropertyMapInfo
	{
		public TransformPropertyMap(ITransformMap<TIn, TOut> transformMap)
		{
			TransformMap = transformMap;
		}

		private ITransformMap<TIn, TOut> TransformMap { get; set; }

		public ITransformPropertyMap<TIn, TOut> From<TProp>(Expression<Func<TIn, TProp>> propFunc)
		{
			MemberExpression memberExpression = propFunc.Body as MemberExpression;
			string propertyName = null;
			Type propertyType = null;

			while (memberExpression != null)
			{
				propertyName += "." + memberExpression.Member.Name;

				var propertyInfo =
					memberExpression.Member.DeclaringType.
					                 GetTypeInfo().GetDeclaredProperty(memberExpression.Member.Name);

				if (propertyInfo != null)
				{
					propertyType = propertyInfo.PropertyType;
				}
				else
				{
					break;
				}

				memberExpression = memberExpression.Expression as MemberExpression;
			}

			if (propertyName == null)
			{
				throw new ArgumentException("No property specified in statement");
			}

			propertyName = propertyName.TrimStart('.');

			PropertyName = propertyName;
			PropertyType = propertyType;

			return this;
		}

		public ITransformMap<TIn, TOut> To<TProp>(Expression<Func<TOut, TProp>> propFunc)
		{
			MemberExpression memberExpression = propFunc.Body as MemberExpression;
			string propertyName = null;
			Type propertyType = null;

			while (memberExpression != null)
			{
				propertyName += "." + memberExpression.Member.Name;

				var propertyInfo =
					memberExpression.Member.DeclaringType.
					                 GetTypeInfo().GetDeclaredProperty(memberExpression.Member.Name);

				if (propertyInfo != null)
				{
					propertyType = propertyInfo.PropertyType;
				}
				else
				{
					break;
				}

				memberExpression = memberExpression.Expression as MemberExpression;
			}

			propertyName = propertyName.TrimStart('.');

			ToPropertyName = propertyName;
			TransformType = propertyType;

			return TransformMap;
		}

		public string PropertyName { get; private set; }

		public string ToPropertyName { get; private set; }

		public Type PropertyType { get; private set; }

		public Type TransformType { get; private set; }
	}
}